package client;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
/***
 * Handles communication with server for client and starts new DownloadFile thread to download asynchronously
 * @author Kim Persson
 */
public class ClientCommunication {
	
	private Socket socket;
	private PrintWriter writer;
	private BufferedReader reader;
	private ArrayList<String> messages;
	private Receiver receiver;
	private ServerClient server;


	
	/**
	 * Default constructor
	 * @param serverIp address of server
	 * @param serverPort port to connect to
	 * @throws UnknownHostException Server can't be found
	 * @throws IOException Communication exception
	 */
	public ClientCommunication(String serverIp, int serverPort, String sharePath) throws UnknownHostException, IOException
	{
		socket = new Socket(serverIp,serverPort);
		socket.setKeepAlive(true);
		writer = new PrintWriter(socket.getOutputStream(), true);
		reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		messages = new ArrayList<String>();
		server = new ServerClient(sharePath);
		server.start();
		receiver = new Receiver();
		receiver.start();
		

	}
	
	/**
	 * Gets server socket in Server Client listens to
	 * @return port number
	 */
	public int getServerPort()
	{
		return server.getServerPort();
	}
	
	/**
	 * Sends command string over socket
	 * @param command String command to send
	 */
	public void send(String command)
	{

		writer.println(command);
	}
	
	/**
	 * Read text from socket and return results
	 * @return results written to inputstream by server
	 * @throws InterruptedException 
	 */
	@SuppressWarnings("unchecked")
	public ArrayList<String> getResults() throws InterruptedException
	{
		ArrayList<String> tmp = new ArrayList<String>();
		synchronized(messages)
		{
			messages.wait(5000);
			tmp = (ArrayList<String>) messages.clone();
			messages.clear();
		}
		return tmp;
	}
	
	/**
	 * Closes all connections to server
	 */
	public void disconnect()
	{
		receiver.disconnect();
		try
		{
			server.disconnect();
			writer.close();
			reader.close();
		} catch (IOException e)
		{
			System.out.println("ERROR: Failed to disconnect " + e.getMessage());
		} finally
		{
			if (!socket.isClosed())
			{
				try {
					socket.close();
				} catch (IOException e) {
					System.out.println("ERROR: Failed to close Socket " + e.getMessage());
				}
			}
		}
	}
	
	/**
	 * Downloads file asynchronously by starting a download thread
	 * @param path where to save file on computer
	 * @param filename name of file
	 * @param size how many bytes to download
	 * @param ip address to client sharing the file
	 * @param port port to connect to
	 * @param client client referens for callbacks
	 * @return reference to download thread object
	 */
	public DownloadFile downloadFile(String path, String filename, int size,String ip, int port, FISHClient client)
	{
		DownloadFile df = new DownloadFile(path,filename, size, ip , port, client);
		df.start();
		return df;
	}

	
	/*******************************************************************************************************
	 * Receives messages over socket, if message is a ping it responds automatically
	 * otherwise it adds message to messages arraylist in ClientCommunication
	 * @author Kim Persson
	 *******************************************************************************************************/
	private class Receiver extends Thread
	{
		private boolean disconnected = false;
		/**
		 * Sets disconnect status to ignore socket errors after they are closed and instead close thread 
		 */
		public void disconnect()
		{
			disconnected = true;
		}
		
		/**
		 * Receives messages over socket, if message is a ping it responds automatically
	     * otherwise it adds message to messages ArrayList in ClientCommunication
		 */
		public void run()
		{
			String msg;
			while(true)
			{
				try {
					msg = reader.readLine();
					if (msg.equals("ping"))
						writer.println("ping");
					else
					{
						synchronized(messages)
						{
							messages.add(msg);
							messages.notifyAll();
						}
					}
				} catch (IOException e) {
					if(!disconnected)
						System.out.println("ERROR: Couldn't receive message " + e.getMessage());
					else 
						return;
				}
			}
		}
	}
	
	
	
	

}
